home *** CD-ROM | disk | FTP | other *** search
/ Macwelt 1 / Macwelt DVD 1.toast / Web-Publishing / HTML-Editoren / Alpha ƒ / Tcl / Modes / sMode.tcl < prev    next >
Encoding:
Text File  |  2001-01-26  |  63.2 KB  |  1,854 lines

  1. ## -*-Tcl-*-  (nowrap)
  2.  # ==========================================================================
  3.  #  Statistical Modes - an extension package for Alpha
  4.  # 
  5.  #  FILE: "sMode.tcl"
  6.  #                                    created: 01/15/00 {07:15:32 pm} 
  7.  #                                last update: 01/26/01 {12:29:02 pm}
  8.  #  Description: 
  9.  #                                 
  10.  #  For S (or S-Plus) syntax files, as well as the free distribution of R.
  11.  #  
  12.  #  Author: Craig Barton Upright
  13.  #  E-mail: <cupright@princeton.edu>
  14.  #    mail: Princeton University,  Department of Sociology
  15.  #          Princeton, New Jersey  08544
  16.  #     www: <http://www.princeton.edu/~cupright>
  17.  #  
  18.  # -------------------------------------------------------------------
  19.  #  
  20.  # Copyright (c) 2000-2001 Craig Barton Upright
  21.  # 
  22.  # This program is free software; you can redistribute it and/or modify
  23.  # it under the terms of the GNU General Public License as published by
  24.  # the Free Software Foundation; either version 2 of the License, or
  25.  # (at your option) any later version.
  26.  # 
  27.  # This program is distributed in the hope that it will be useful,
  28.  # but WITHOUT ANY WARRANTY; without even the implied warranty of
  29.  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  30.  # GNU General Public License for more details.
  31.  # 
  32.  # You should have received a copy of the GNU General Public License
  33.  # along with this program; if not, write to the Free Software
  34.  # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  35.  # 
  36.  # ==========================================================================
  37.  ##
  38.  
  39. # ===========================================================================
  40. #
  41. # ◊◊◊◊ Initialization of S mode ◊◊◊◊ #
  42.  
  43. alpha::mode S 2.1.1 sMenu {*.s *.S *.R} {
  44.     sMenu electricReturn electricTab electricBraces
  45. } {
  46.     # We require 7.4b21 for prefs handling.
  47.     alpha::package require -loose AlphaTcl 7.4b21
  48.     addMenu sMenu "S+/R" S
  49.     set unixMode(splus) {S}
  50. } uninstall {
  51.     catch {file delete [file join $HOME Tcl Modes sMode.tcl]}
  52.     catch {file delete [file join $HOME Tcl Completions SCompletions.tcl]}
  53.     catch {file delete [file join $HOME Tcl Completions "S Tutorial.s"]}
  54. } help {
  55.     file "Statistical Modes Help"
  56. } maintainer {
  57.     "Craig Barton Upright" <cupright@princeton.edu> 
  58.     <http://www.princeton.edu/~cupright/>
  59. }
  60.  
  61. hook::register quitHook S::quitHook
  62.  
  63. proc sMenu {} {}
  64.  
  65. proc sMode.tcl {} {}
  66.  
  67. namespace eval S {}
  68.  
  69. # ===========================================================================
  70. #
  71. # ◊◊◊◊ Setting S mode variables ◊◊◊◊ #
  72. #
  73.  
  74. # Removing obsolete preferences from earlier versions.
  75.  
  76. set oldvars {
  77.     don'tRemindMe funcExpr parseExpr keywordColor eitherorColor
  78.     functionColor useMagicCharacter eitherOrs eitherOrColor sHelp
  79. }
  80.  
  81. foreach oldvar $oldvars {prefs::removeObsolete SmodeVars($oldvar)}
  82.  
  83. unset oldvar oldvars
  84.  
  85. # ===========================================================================
  86. #
  87. # Standard preferences recognized by various Alpha procs
  88. #
  89.  
  90. newPref var  leftFillColumn     {0}                     S
  91. newPref var  fillColumn         {75}                    S
  92. newPref var  prefixString       {# }                    S
  93. newPref var  wordBreak          {[-a-zA-Z0-9\._]+}      S
  94. newPref var  wordBreakPreface   {[^-a-zA-Z0-9\._]}      S
  95. newPref flag wordWrap           {0}                     S
  96.  
  97. # ===========================================================================
  98. #
  99. # Flag preferences
  100. #
  101.  
  102. newPref flag autoMark           {0}     S   {S::rebuildMenu markSFileAs}
  103.  
  104. # By default command double-click will send a command to on-line help, and
  105. # option double-click sends a command to the local S-Plus application. 
  106. # Check this box to switch these key combinations.
  107. newPref flag localHelp          {0}     S   {S::rebuildMenu sMenu}
  108.  
  109. # Check this box if your keyboard does not have a "Help" key.  This will
  110. # change some of the menu's key bindings.
  111. newPref flag noHelpKey          {0}     S   {S::rebuildMenu sMenu}
  112.  
  113. # Check this preference to use Venable and Ripley's MASS library for keyword
  114. # colorizing and completions
  115. newPref flag useMassLibrary     {1}     S   {S::colorizeS}
  116.  
  117. # Set the list of flag preferences which can be changed in the menu.
  118.  
  119. set SPrefsInMenu [list          \
  120.   "localHelp"                   \
  121.   "noHelpKey"                   \
  122.   "useMassLibrary"              \
  123.   ]
  124.  
  125. # ===========================================================================
  126. #
  127. # Variable preferences
  128.  
  129. # Enter additional arguments to be colorized. 
  130. newPref var addArguments        {c dimnames list plot replace} S {S::colorizeS}
  131.  
  132. # Enter additional S commands to be colorized.
  133. newPref var addCommands         {print} S   {S::colorizeS}
  134.  
  135. # Select the statistical application to be used.
  136. newPref var application         {S+}    S   {S::rebuildMenu sMenu} [list R S+]
  137.  
  138. # Command double-clicking on an S keyword will send it to this url for a
  139. # help reference page.
  140. newPref url helpUrl {http://stat.ethz.ch/R-alpha/library/base/html/}    S
  141.  
  142. # The "R Home Page" menu item will send this url to your browser.
  143. newPref url rHomePage           {http://cran.r-project.org/}    S
  144.  
  145. # Click on "Set" to find the local R application.
  146. newPref sig rSig                {}      S   {}
  147.  
  148. # The "S+ Home Page" menu item will send this url to your browser.
  149. newPref url s+HomePage          {http://www.splus.mathsoft.com/}        S
  150.  
  151. # Click on "Set" to find the local S+ application.  (As of this writing
  152. # there are no such applications for the Macintosh.)
  153. newPref sig s+Sig               {}      S   {}
  154.  
  155. # ===========================================================================
  156. #
  157. # Color preferences
  158. #
  159. # Nomenclature notes:
  160. # S-Plus is remarkably elegant in structure.  Commands have arguments, and
  161. # rarely does the language use the same names for both.  There are a few
  162. # exceptions, listed initially in the argument category.  
  163. #
  164.  
  165. # See the Statistical Modes Help file for an explanation of these different
  166. # categories, and lists of keywords.
  167. newPref color argumentColor     {magenta}       S   {S::colorizeS}
  168. newPref color commandColor      {blue}          S   {S::colorizeS}
  169. newPref color commentColor      {red}           S   {stringColorProc}
  170.  
  171. # Color of the magic character $.  Magic Characters will colorize any
  172. # string which follows them, up to the next empty space.
  173. newPref color magicColor        {black}         S   {S::colorizeS}
  174.  
  175. newPref color stringColor       {green}         S   {stringColorProc}
  176.  
  177. # The color of symbols such as "/", "@", etc.
  178. newPref color symbolColor       {magenta}       S   {S::colorizeS}
  179.  
  180. regModeKeywords -e {#}                  \
  181.   -c $SmodeVars(commentColor)           \
  182.   -s $SmodeVars(stringColor)  S {}
  183.  
  184. # ===========================================================================
  185. #
  186. # Flag Flip
  187. # Called by menu items, change the value of flag preferences.
  188.  
  189. proc S::flagFlip {pref} {
  190.  
  191.     global mode SmodeVars
  192.     
  193.     set SmodeVars($pref) [expr {$SmodeVars($pref) ? 0 : 1}]
  194.     set oldMode $mode
  195.     set mode "S"
  196.     synchroniseModeVar $pref $SmodeVars($pref)
  197.     set mode $oldMode
  198.     if {$SmodeVars($pref)} {
  199.         set end "on"
  200.     } else {
  201.         set end "off"
  202.     }
  203.     message "The \"$pref\" preference is now $end."
  204. }
  205.  
  206. # ===========================================================================
  207. #
  208. # Comment Character variables for Comment Line / Paragraph / Box menu items.
  209.  
  210. set S::commentCharacters(General)   "# "
  211. set S::commentCharacters(Paragraph) [list "## " " ##" " # "]
  212. set S::commentCharacters(Box)       [list "#" 1 "#" 1 "#" 3]
  213.  
  214. # ===========================================================================
  215. #
  216. # ◊◊◊◊ Keyword Dictionaries ◊◊◊◊ #
  217. #
  218.  
  219. # Making sure that SUserCommands and SUserArguments exist.
  220. # These will be over-ridden if they are loaded from a ${mode}Prefs.tcl file.
  221. #
  222.  
  223. set SUserCommands       ""
  224. set SUserArguments      ""
  225.  
  226. # ===========================================================================
  227. #
  228. # ◊◊◊◊   S Commands   ◊◊◊◊ #
  229. #
  230.  
  231. set SCommands {
  232.     abbreviate abline abs ace acf acf.plot adm.ave adm.filt adm.smo acos
  233.     add1 aggregate aggregrate.ts agnes akima alias all all.equal allocated
  234.     anova any aov aov.genyates aperm append apply approx ar ar.burg ar.gm
  235.     ar.yw arg.dialog args arima.diag arima.filt arima.forecast
  236.     arima.fracdiff arima.fracdiff.sim arima.mle arima.sim arima.td array
  237.     arrows as.character as.data.frame as.data.frame.array as.data.frame.ts
  238.     as.matrix as.numeric as.vector as.xxx asin assign atan attach attr
  239.     attributes avas axis backsolve banking barchart barplot BATCH bcv
  240.     binomial biplot biplot.default bootstrap boxplay browser brush bs
  241.     butterfly bwplot by c cancor cat cbind cdf.compare ceiling cex
  242.     character charmatch chissq.gof chol clara class close.screen cloud
  243.     cmdscale coef coefficients contour countourplot contr.helmert
  244.     contr.poly contr.sdif contr.sum contr.treatment contrasts cor cor.test
  245.     correlogram cos cosh count.fields cov.mve cov.wt cox.zph coxph
  246.     crossprod crosstabs cts cummax cummin cumprod cumsum cut cutree cv.tree
  247.     D daisy data.class data.dump data.frame data.matrix data.restore
  248.     database.object date dates dbwrite debugger demod density densityplot
  249.     deparse deriv deriv3 design det detach dev.ask dev.copy dev.cur
  250.     dev.list dev.next dev.off dev.prev dev.print dev.set deviance dget diag
  251.     Diagonal diana diff dim dimnames dist dmvnorm do.call dos dos.time
  252.     dotchart dotplot dput drop drop1 dummy.corf dump dump.calls dump.frames
  253.     dumpdata duplicated ed eigen equal.count Error eval exists exp
  254.     expand.grid expcov expn expression F fac/desogm faces factanal factor
  255.     family fanny fft fig file.exists filter find .First .First.lib
  256.     .First.local fitted fitted.values fix fixed.effects floor for format
  257.     formula fpl fractionate frame frequency.polygram symbol gam gam.plot
  258.     gamma gaucov gaussian get glm glm.links glm.variances graphics.off
  259.     graphsheet grep hclust help help.off help.start hist hist.FD hist.scott
  260.     hist2d histogram history hpgl hplg I() identify if ifelse Im image
  261.     inspect integrate interaction.plot interp inverse.gaussian invisible
  262.     iris4d is.characger is.na is.random is.xxx its julian Kaver keep.order
  263.     Kenvl key Kfn kmeans kruskal.test ks.gof ksmooth l1fit lag lapply .Last
  264.     last.dump .Last.value leaps legend length letters levelplot levels
  265.     lgamma library limits.bca limits.emp lines list lm lm.influence lme
  266.     lmsreg lo loadings location.m locator loess log log10 loglin lower.tri
  267.     lowess ltsreg lu mad mahalanobis mai make.call make.family make.fileds
  268.     make.groups manova mar masked mat2tr match match.arg matplot matrix
  269.     Matrix.class max mclass mclust mean median memory.size merge mex mfcol
  270.     mfrow min misclass.tree missing mkh mode model.frame.tree model.matrix
  271.     model.tables mona monthplot motif mreloc ms mstree mtext multinom
  272.     na.action na.fail na.gam.replace na.omit names nchar nclass.FD
  273.     nclass.scott ncol neg.bin next NextMethod nlme nlminb nlregb nls
  274.     nlsList nnet nnet.Hess nnls.fit norm nroff nrow ns ntrellis numeric
  275.     as.design objdiff objects offset oma omd omi on.exit openlook optimize
  276.     optimize options .Options order ordered outer output pairs pam par
  277.     partition.tree paste pdf.graph persp persp.setup perspp pi pie piechart
  278.     plclust plot.gam plot.survfit pltree pmatch pmax pmin pmvnorm pnorm
  279.     points poisson poly polygon polyroot post.tree postscript ppinit pplik
  280.     ppoints ppreg ppregion prcomp predict predict.factanal predict.gam
  281.     predict.lm predict.lme predict.tree princomp print.summary
  282.     print.trellis printgraph prmat proc.time prod profile proj prompt
  283.     prompt.screen prune.misclass prune.tree Psim pty q qda qqline qqnorm
  284.     qqplot qr qr.coef qr.fitted qr.Q qr.R qr.resid qr.X quantile quasi
  285.     .Random.seed range rank raov rbind rbiwt rcond Re read.table Recall
  286.     remove reorder.factor rep repeat replications resid residuals restart
  287.     return rev rm rmv rmvnorm rnorm rotate rotate.default round row
  288.     row.names RowPermutation Rows tpois rreg rts rug s sabl sample sapply
  289.     scale scale.a scale.tau scan scatter.smooth screen screenplot
  290.     se.contrast search segments semat seq set.seed show.settings sign
  291.     signig sin sinh sink slice.index slm smooth.spline solve solve.qr
  292.     solve.upper sort sort.list source spatial spec.ar spec.pgram spec.taper
  293.     spectrum sphercov spin spline split split.screen splom sqrt SSI stars
  294.     state.name statlib stdres stem step stepAIC stepfun stepwise stl stop
  295.     Strauss stripplot structure studres subplot subset substutute substring
  296.     sum summary summary.coxph summary.gam summary.lm supsmu surf.gls
  297.     surf.ls Surv survdiff survexp survfit survreg svd sweep switch symbols
  298.     synchronize sys.parent system t t.test table tan tanh tapply tempfile
  299.     terms text text.default title tprint trace traceback tree tree.control
  300.     trellis trellis.3d.args trellis.args trellis.device trellis.par.get
  301.     trellis.par.set trmat tue.file.name trunc ts.intersect ts.lines ts.plot
  302.     ts.points ts.union tspar ttest twoway unclass unique uniroot unix
  303.     unix.time unlink unlist unpack update usa UseMethod usr var var.test
  304.     varcomp variogram vcov.nlminb vcov.mlreg becnorm vi warning while
  305.     wilcox.text win.colorscheme win.graph win.printer win3 window wireframe
  306.     write write.table xor xyplot
  307.  
  308. # ===========================================================================
  309. #
  310. # ◊◊◊◊   S Arguments   ◊◊◊◊ #
  311. #
  312.  
  313. set SArguments {
  314.     add aic all angle append as.is aux axes bandwidth best border box.ratio
  315.     boxplots byrow center circles cohort col.names collapse conditional
  316.     conf.int constant cor cuts data decay degree delta demean density depth
  317.     detail detrend device df dframe differences dimmames.write dist drape
  318.     eig else end entropy erase et evaluate exclude extrap factors family
  319.     fence file fileout fill first frame frequency FUN full.precision fun
  320.     gof.lag gradient h head header height help Hess hessian highlight hist
  321.     horizontal in inches individual int inter.max intercept inverse
  322.     inverted iter jacobian jitter k kernel labels lag lims link lineout
  323.     local low lower lty lwd max max.subdiv maxit menu message method metric
  324.     more multi.line n NA na.action na.last na.rm name ndeltat new nf ng
  325.     niter noise normalize nu NULL nv offline onefile only.values orthogonal
  326.     p parameters partial pattern pivot plane plotit pos prior prob
  327.     probability probs psi.fun rang rectangles reverse rho rotation save
  328.     scale scores se.fit sep short side sim simplify skip softmax span spar
  329.     spin squares stars start subset summ symmetric taper test thermometers
  330.     ticks tol trace trim tuning twodig type upper v var.axes what where
  331.     which window wt x xl xlab xu y yl ylab yu
  332. }
  333.  
  334. # ===========================================================================
  335. #
  336. # ◊◊◊◊   S Mass Library   ◊◊◊◊ #
  337. #
  338.  
  339. set SMassLibrary {
  340.     Aids2 Boston Cars93 Choleski Cushings DDT GAGurine IQR Insurance
  341.     Melanoma OME Pima.tr Rabbit Rubber Sitka Sitka89 Skye Traffic
  342.     UScereal UScrime abbey accdeaths addterm animals anova.negbin area
  343.     austres bcv beaver1 beaver2 biopsy biplot.princomp birthwt boxcox cats
  344.     cement chem coop corresp cov.trob cpgram cpus crabs deaths digamma
  345.     drivers dropterm eqscplot faithful farms fdeaths fgl forbes fractions
  346.     galaxies gamma.dispersion gamma.shape.glm gehan genotype gilgais ginv
  347.     glm.convert glm.nb hills histplot huber hubers immer isoMDS janka kde2d
  348.     lda ldahist leuk lh loglm logtrans mammals mca mcycle mdeaths menarche
  349.     michelson minn38 motors mvrnorm negative.binomial newcomb nottem npr1
  350.     oats painters pairs.lda petrol phones plot.lda plot.mca predict.lda
  351.     predict.mca predict.qda qda quine rational rlm rms.curv rnegbin road
  352.     rock rotifer sammon ships shoes shrimp shuttle snails stdres steam
  353.     stepAIC stormer studres summary.loglm summary.negbin summary.rlm survey
  354.     synth.tr theta.md theta.mm topo trees trigamma truehist ucv vcov
  355.     vcov.nlregb waders width.SJ write.matrix wtloss
  356. }
  357.  
  358. # ===========================================================================
  359. # Colorize S.
  360. # Set all keyword lists, and colorize.
  361. # Could also be called in a <mode>Prefs.tcl file
  362.  
  363. proc S::colorizeS {{pref ""}} {
  364.     
  365.     global SmodeVars SCommands SArguments SMassLibrary 
  366.     global SUserCommands SUserArguments Scmds SCommandList
  367.     
  368.     # First setting aside only the commands, for generic completions.
  369.     set SCommandList [concat \
  370.       $SCommands $SmodeVars(addCommands) $SUserCommands]
  371.     if {$SmodeVars(useMassLibrary)} {
  372.         append SCommandList " $SMassLibrary"
  373.     }
  374.     # Then, create the list of all keywords for completions.
  375.     set Scmds [lsort [lunique [concat \
  376.       $SCommandList $SArguments $SmodeVars(addArguments) $SUserArguments \
  377.       ]]]
  378.  
  379.     # Commands
  380.     regModeKeywords -a -k $SmodeVars(commandColor) S $SCommandList 
  381.  
  382.     if {$SmodeVars(useMassLibrary)} {
  383.         regModeKeywords -a -k $SmodeVars(commandColor) S $SMassLibrary
  384.     } else {
  385.         regModeKeywords -a -k {none} S $SMassLibrary
  386.     }
  387.     # Arguments
  388.     set SArgumentColorList [concat \
  389.       $SArguments  $SmodeVars(addArguments) $SUserArguments]
  390.     regModeKeywords -a -k $SmodeVars(argumentColor) S $SArgumentColorList
  391.     
  392.     # Symbols
  393.     regModeKeywords -a                                                  \
  394.       -m {$}                                                            \
  395.       -k $SmodeVars(magicColor) S {}                                    \
  396.       -i "+" -i "-" -i "*" -i "_" -i "\\"                               \
  397.       -I $SmodeVars(symbolColor) 
  398.  
  399.     if {$pref != ""} {refresh}
  400.     if {$pref == "useMassLibrary"} {S::rebuildMenu sMenu} 
  401. }
  402.  
  403. # Call this now.
  404.  
  405. S::colorizeS
  406.  
  407. # ===========================================================================
  408. #
  409. # Reload Completions.  
  410. # This is now an obsolete proc.
  411.  
  412. proc S::reloadCompletions {} {
  413.     alertnote "\"S::reloadCompletions\" is an obsolete proc.\
  414.       It should be removed from your SPrefs.tcl file."
  415. }
  416.  
  417. # ===========================================================================
  418. #
  419. # ◊◊◊◊ Key Bindings, Electrics ◊◊◊◊ #
  420.  
  421. # Known bug: Key-bindings from other global menus might conflict with those
  422. # defined in the Stata menu.  This will help ensure that this doesn't happen.
  423.  
  424. Bind 's'    <cs>    {S::switchToS ""} S
  425. Bind 'p'    <cs>    {S::processFile} S
  426. Bind 'p'    <csz>   {S::processSelection} S
  427. Bind 'p'    <cs>    {S::insertPath} S
  428.  
  429. Bind 'n'    <sz>    {S::nextCommand} S
  430. Bind 'p'    <sz>    {S::prevCommand} S
  431. Bind 's'    <sz>    {S::selectCommand} S
  432. Bind 'c'    <sz>    {S::copyCommand} S
  433.  
  434. Bind 'i'    <cz>    {S::reformatCommand} S
  435.  
  436. Bind '\r'   <s>     {S::continueCommand} S
  437. Bind '\)'           {S::electricRight "\)"} S
  438.  
  439. # For those that would rather use arrow keys to navigate.  Up and down
  440. # arrow keys will advance to next/prev command, right and left will also
  441. # set the cursor to the top of the window.
  442.  
  443. Bind    up  <sz>    {S::prevCommand 0 0} S
  444. Bind  left  <sz>    {S::prevCommand 0 1} S
  445. Bind  down  <sz>    {S::nextCommand 0 0} S
  446. Bind right  <sz>    {S::nextCommand 0 1} S
  447.  
  448. # ===========================================================================
  449. # S Carriage Return
  450. # Inserts a carriage return, and indents properly.
  451.  
  452. proc S::carriageReturn {} {
  453.     
  454.     global SmodeVars
  455.     
  456.     if {[isSelection]} {deleteSelection} 
  457.     
  458.     set pos1 [lineStart [getPos]]
  459.     set pos2 [getPos]
  460.     if {[regexp {^([\t ])*(\}|\)|dev\.off)} [getText $pos1 $pos2]]} {
  461.         createTMark temp $pos2
  462.         catch {bind::IndentLine}
  463.         gotoTMark temp ; removeTMark temp
  464.     } 
  465.     insertText "\r"
  466.     catch {bind::IndentLine}
  467. }
  468.  
  469. # ===========================================================================
  470. #
  471. # Electric Left, Right
  472. # Adapted from "tclMode.tcl"
  473.  
  474. proc S::electricLeft {} {
  475.  
  476.     if {[literalChar]} {
  477.         typeText "\{"
  478.         return
  479.     }
  480.     set pat "\}\[ \t\r\n\]*(else(if)?)\[ \t\r\n\]*\$"
  481.     set pos [getPos]
  482.     if { [set result [findPatJustBefore "\}" $pat $pos word]] == "" } { 
  483.         insertText "\{"
  484.         return
  485.     }
  486.     # we have an if/else(if)/else
  487.     switch -- $word {
  488.         "else" {
  489.             deleteText [lindex $result 0] $pos
  490.             elec::Insertion "\} $word \{\r\t••\r\}\r••"
  491.         }
  492.         "elseif" {
  493.             deleteText [lindex $result 0] $pos
  494.             elec::Insertion "\} $word \{••\} \{\r\t••\r\}\r••"
  495.         }
  496.     }
  497. }
  498.     
  499. proc S::electricRight {{char "\}"}} {
  500.     
  501.     if {[literalChar]} {
  502.         typeText $char
  503.         return
  504.     }
  505.     set pos [getPos]
  506.     typeText $char
  507.     if {![regexp {[^ \t]} [getText [lineStart $pos] $pos]]} {
  508.         set pos [lineStart $pos]
  509.         createTMark temp [getPos]
  510.         catch {bind::IndentLine}
  511.         gotoTMark temp ; removeTMark temp
  512.         bind::CarriageReturn
  513.     } 
  514.     if {[catch {blink [matchIt $char [pos::math $pos - 1]]}]} {
  515.         beep ; message "No matching $char !!"
  516.     } 
  517. }
  518.  
  519. # ===========================================================================
  520. #
  521. # Continue Command
  522. # Over-rides the automatic indentation of lines that begin with \} or \)
  523. # so that additional text can be entered.
  524.  
  525. proc S::continueCommand {} {
  526.  
  527.     global indent_amounts
  528.     
  529.     bind::CarriageReturn
  530.     if {[pos::compare [getPos] != [maxPos]]} {
  531.         set nextChar [getText [getPos] [pos::math [getPos] + 1]]
  532.         if {$nextChar == "\}" || $nextChar == "\)"} {
  533.             insertText [text::indentOf $indent_amounts(2)]
  534.         } 
  535.     } 
  536. }
  537.  
  538. # ===========================================================================
  539. #
  540. # ◊◊◊◊ Indentation ◊◊◊◊ #
  541. # S::correctIndentation is necessary for Smart Paste, and returns the
  542. # correct level of indentation for the current line.  S::indentLine uses
  543. # this level to indent the current line.
  544. # In S::correctIndentation, we grab the previous non-commented line, remove
  545. # all of the characters besides braces, quotes, and hashmarks, and then
  546. # convert it all to a list to be evaluated.  Braces and hashmarks contained
  547. # within quotes, as well as literal characters, should all be ignored and
  548. # the remaining braces are used to determine the correct level of nesting.
  549.  
  550. proc S::indentLine {{pos ""}} {
  551.     
  552.     if {$pos == ""} {set pos [getPos]} 
  553.     # Get details of current line.
  554.     set posBeg [lineStart [getPos]]
  555.     set text [getText $posBeg [nextLineStart $posBeg]]
  556.     regexp {^[ \t]*} $text white
  557.     set posNext1 [pos::math $posBeg + [string length $white]]
  558.     set posNext2 [pos::math $posNext1 + 1]
  559.     if {[pos::compare $posNext2 > [maxPos]]} {
  560.         set posNext2 [maxPos]
  561.     } 
  562.     # Determine the correct level of indentation for this line, given the
  563.     # next character.
  564.     set lwhite [S::correctIndentation $pos [getText $posNext1 $posNext2]]
  565.     set lwhite [text::indentOf $lwhite]
  566.     if {$white != $lwhite} {
  567.         replaceText $posBeg $posNext1 $lwhite
  568.     }
  569.     goto [pos::math $posBeg + [string length $lwhite]]
  570. }
  571.  
  572. proc S::correctIndentation {pos {next ""}} {
  573.     
  574.     global indent_amounts SmodeVars
  575.     
  576.     set posBeg   [lineStart $pos]
  577.     # Get information about this line, previous line ...
  578.     set thisLine  [S::getCommandLine $posBeg 1 1]
  579.     set prevLine1 [S::getCommandLine [pos::math $posBeg - 1] 0 1]
  580.     set prevLine2 [S::getCommandLine [pos::math [lindex $prevLine1 0] - 1] 0 1]
  581.     set lwhite    [lindex $prevLine1 1]
  582.     # If we have a previous line ...
  583.     if {[pos::compare [lindex $prevLine1 0] != $posBeg]} {
  584.         # Indent if the preceding command was a postscript command.
  585.         set pL1 [string trim [lindex $prevLine1 2]]
  586.         if {[regexp {^[\t ]*postscript([\t ]*\()} $pL1]} {
  587.             incr lwhite $indent_amounts(2)
  588.         } 
  589.         # Indent if the last line did not terminate the command.
  590.         if {[string trimright $pL1 "\\"] != $pL1} {
  591.             incr lwhite $indent_amounts(1)
  592.         } 
  593.         # Check to make sure that the previous command was not itself a
  594.         # continuation of the line before it.
  595.         if {[pos::compare [lindex $prevLine2 0] != [lindex $prevLine1 0]]} {
  596.             set pL2 [string trim [lindex $prevLine2 2]]
  597.             if {[string trimright $pL2 "\\"] != $pL2} {
  598.                 incr lwhite $indent_amounts(-1)
  599.             } 
  600.         } 
  601.         # Find out if there are any unbalanced {,},(,) in the last line.
  602.         regsub -all {[^ \{\}\(\)\"\#\\]} $pL1 { } line
  603.         # Remove all literals.
  604.         regsub -all {\\\{|\\\}|\\\(|\\\)|\\\"|\\\#} $line { } line
  605.         regsub -all {\\} $line { } line
  606.         # Remove everything surrounded by quotes.
  607.         regsub -all {\"([^\"]+)\"} $line { } line
  608.         regsub -all {\"} $line { } line
  609.         # Remove all characters following the first valid comment.
  610.         if {[regexp {\#} $line]} {
  611.             set line [string range $line 0 [string first {#} $line]]
  612.         } 
  613.         # Now turn all braces into 2's and -2's
  614.         regsub -all {\{|\(} $line { 2 }  line
  615.         regsub -all {\}|\)} $line { -2 } line
  616.         # This list should now only contain 2's and -2's.
  617.         foreach i $line {
  618.             if {$i == "2" || $i == "-2"} {incr lwhite $indent_amounts($i)} 
  619.         }
  620.         # Did the last line start with a lone \) or \} ?  If so, we want to
  621.         # keep the indent, and not make call it an unbalanced line.
  622.         if {[regexp {^[\t ]*(\}|\))} $pL1]} {
  623.             incr lwhite $indent_amounts(2)
  624.         } 
  625.     } 
  626.     # If we have a current line ...
  627.     if {[pos::compare [lindex $thisLine 0] == $posBeg]} {
  628.         # Reduce the indent if the first non-whitespace character of this
  629.         # line is ) or \}.
  630.         set tL [lindex $thisLine 2]
  631.         if {$next == "\}" || $next == ")" || [regexp {^[\t ]*(\}|\)|dev\.off)} $tL]} {
  632.             incr lwhite $indent_amounts(-2)
  633.         } 
  634.     } 
  635.     # Now we return the level to the calling proc.
  636.     return [expr {$lwhite > 0 ? $lwhite : 0}]
  637. }
  638.  
  639. # ===========================================================================
  640. # Get Command Line
  641. # Find the next/prev command line relative to a given position, and return
  642. # the position in which it starts, its indentation, and the complete text
  643. # of the command line.  If the search for the next/prev command fails,
  644. # return an indentation level of 0.
  645.  
  646. proc S::getCommandLine {pos {direction 1} {ignoreComments 1}} {
  647.     
  648.     if {$ignoreComments} {
  649.         set pat {^[\t ]*[^\t\r\n\# ]}
  650.     } else {
  651.         set pat {^[\t ]*[^\t\r\n ]}
  652.     } 
  653.     set posBeg [pos::math [lineStart $pos] - 1]
  654.     if {[pos::compare $posBeg < [minPos]]} {
  655.         set posBeg [minPos]
  656.     } 
  657.     set lwhite 0
  658.     if {![catch {search -f $direction -r 1 $pat $pos} match]} {
  659.         set posBeg [lindex $match 0]
  660.         set lwhite [posX [pos::math [lindex $match 1] - 1]]
  661.     }
  662.     set posEnd [pos::math [nextLineStart $posBeg] - 1]
  663.     if {[pos::compare $posEnd > [maxPos]]} {
  664.         set posEnd [maxPos]
  665.     } 
  666.     return [list $posBeg $lwhite [getText $posBeg $posEnd]]
  667. }
  668.  
  669. # ===========================================================================
  670. # ◊◊◊◊ Command Double Click ◊◊◊◊ #
  671. #
  672. # Checks to see if the highlighted word appears in any keyword list, and if
  673. # so, sends the selected word to the www.mathsoft.com help site.
  674. # (The above is not yet implemented -- where's a S help site ???)
  675. #
  676. # Control-Command double click will insert syntax information in status bar.
  677. # Shift-Command double click will insert commented syntax information in window.
  678. # (The above is not yet implemented -- need to enter all of the syntax info.)
  679.  
  680. proc S::DblClick {from to shift option control} {
  681.     
  682.     # First make sure that Scmds has been defined.
  683.     
  684.     SCompletions.tcl
  685.     
  686.     global SmodeVars Scmds SSyntaxMessage
  687.         
  688.     set where [getPos]
  689.     
  690.     select $from $to
  691.     set command [getSelect]
  692.     
  693.     set varDef "$command+\[\t \]+(<\-|_)"
  694.     
  695.     if {![catch {search -s -f 1 -r 1 -m 0 $varDef [minPos]} match]} {
  696.         # First check current file for a variable (etc) definition, and if
  697.         # found ...
  698.         placeBookmark
  699.         goto [lineStart [lindex $match 0]]
  700.         message "press <Ctl .> to return to original cursor position"
  701.         return
  702.         # Could next check any open windows, or files in the current
  703.         # window's folder ...  but not implemented.  For now, variables
  704.         # (etc) need to be defined in current file.
  705.     } elseif {[lsearch -exact $Scmds $command] == -1} {
  706.         message "\"$command\" is not defined as an S system keyword."
  707.         return
  708.     }
  709.     # Defined as a keyword, determine if there's a syntax message.
  710.     # Any modifiers pressed?
  711.     if {$control} {
  712.         # CONTROL -- Just put syntax message in status bar window
  713.         if {[info exists SSyntaxMessage($command)]} {
  714.             message "$SSyntaxMessage($command)"        
  715.         } else {
  716.             message "Sorry, no syntax information available for $command"
  717.         } 
  718.     } elseif {$shift} {
  719.         # SHIFT --Just insert syntax message as commented text
  720.         if {[info exists SSyntaxMessage($command)]} {
  721.             endOfLine
  722.             insertText "\r"
  723.             insertText "$SSyntaxMessage($command)"
  724.             comment::Line
  725.         } else {
  726.             message "Sorry, no syntax information available for $command"
  727.         }
  728.     } elseif {$option && !$SmodeVars(localHelp)} {
  729.         # Now we have four possibilities, based on "option" key and the
  730.         # preference for "local Help".
  731.         # 
  732.         # OPTION, local help isn't checked -- Send command to local application
  733.         S::localCommandHelp $command
  734.     } elseif {$option && $SmodeVars(localHelp)} {
  735.         # OPTION, but local help is checked -- Send command for on-line help.
  736.         S::wwwCommandHelp $command
  737.     } elseif {$SmodeVars(localHelp)} {
  738.         # No modifiers, local help is checked -- Send command to local app.
  739.         S::localCommandHelp $command
  740.     } else {
  741.         # No modifiers, no local help checked -- Send command for on-line
  742.         # help.  This is the "default" behavior.
  743.         S::wwwCommandHelp $command
  744.     }
  745. }
  746.  
  747. # ===========================================================================
  748. # WWW Command Help
  749. # Send command to defined url, prompting for text if necessary.
  750.  
  751. proc S::wwwCommandHelp {{command ""}} {
  752.     
  753.     global SmodeVars
  754.     
  755.     if {$command == ""} {
  756.         set command [prompt "on-line S+/R help for ... " [getSelect]] 
  757.         # set command [statusPrompt "on-line help for ... " ] 
  758.     } 
  759.     message "\"$command\" sent to $SmodeVars(helpUrl)"
  760.     icURL $SmodeVars(helpUrl)${command}.html
  761. }
  762.  
  763. # ===========================================================================
  764. # Local Command Help
  765. # Find a local help file, and open it in a browser.
  766. # Prompt for text if necessary.
  767. # We're assuming that the help does exist as a file somewhere, as opposed
  768. # to being an internal application help function.  At the moment, we also
  769. # assume that this file is html, although that could be a mode option as
  770. # well.
  771. # This needs more work ...
  772.  
  773. proc S::localCommandHelp {{command ""}} {
  774.     
  775.     global SmodeVars
  776.     
  777.     set app $SmodeVars(application)
  778.  
  779.     if {$command == ""} {
  780.         set command [prompt "local $app application help for ... " [getSelect]] 
  781.         # set command [statusPrompt "local S application help for ... " ] 
  782.     } 
  783.     S::processSelection "help ($command)" "$app"
  784. }
  785.  
  786. # proc S::localCommandHelp {{command ""} {app ""}} {
  787. #     
  788. #     global SmodeVars tcl_platform
  789. #     
  790. #     if {$app == ""} {
  791. #         set app $SmodeVars(application)
  792. #     } 
  793. #     if {$command == ""} {
  794. #         set command [prompt "local $app application help for ... " [getSelect]]
  795. #         # set command [statusPrompt "local S-Plus application help for ..." ]
  796. #     }
  797. #     set pf $tcl_platform(platform)
  798. #     
  799. #     # We have six possible options here, based on platform and application.
  800. #     # For each option, we want to create the path to the help file.
  801. #     
  802. #     if {$pf == "macintosh"} {
  803. #         # We'll kill this right now.  The rest is for future code ...
  804. #         S::betaMessage 
  805. #         # Make sure that the Macintosh application for the signature exists.
  806. #         if {[catch {[nameFromAppl [S::sig $app]]}]} {
  807. #             S::setApplication $app
  808. #         } 
  809. #         if {$SmodeVars(application) == "R"} {
  810. #             # Macintosh, R
  811. #         } else {
  812. #             # Macintosh, S+
  813. #         }
  814. #     } elseif {$pf == "windows" || $pf == "unix"} {
  815. #         # Make sure that the Windows application for the signature exists. 
  816. #         # We assume that this will work for unix, too.
  817. #         if {![file exists [S::sig $app]]} {
  818. #             S::setApplication $app
  819. #         } 
  820. #         if {$SmodeVars(application) == "R"} {
  821. #             # Windows, R
  822. #             set appRoot  [file dirname [file dirname [S::sig]]]
  823. #             set helpLib  [file join $appRoot library base html]
  824. #             set helpFile [file join $helpLib ${command}.html]
  825. #         } else {
  826. #             # Windows, S+
  827. #             S::betaMessage
  828. #         }
  829. #     }
  830. #     # Now we look for the actual help file.
  831. #     if {![file exists $helpFile]} {
  832. #         beep ; message "Sorry, no help file for \"$command\" was found."
  833. #         error "No help file found for \"$command\"."
  834. #     } else {
  835. #         help::openFile $helpFile 
  836. #     } 
  837. # }
  838.  
  839.  
  840. # ===========================================================================
  841. #
  842. # ◊◊◊◊ Mark File and Parse Functions ◊◊◊◊ #
  843. #
  844.  
  845. # ===========================================================================
  846. #
  847. # S Mark File
  848. # This will return the first 35 characters from the first non-commented
  849. # word that appears in column 0.  All other output files (those not
  850. # recognized) will take into account the additional left margin elements
  851. # added by S+/R.
  852. #
  853.  
  854. proc S::MarkFile {{type ""}} {
  855.     
  856.     removeAllMarks
  857.     
  858.     message "Marking File …"
  859.     
  860.     set pos [minPos]
  861.     set count 0
  862.     # Figure out what type of file this is -- source, or output.
  863.     # The variable "type" refers to a call from the S menu.
  864.     # Otherwise we try to figure out the type based on the file's suffix.
  865.     if {$type == ""} {
  866.         if {[win::CurrentTail] == "* S Mode Example *"} {
  867.             # Special case for Mode Examples, but only if called from
  868.             # Marks menu.  (Called from S menu, "type" will over-ride.)
  869.             set type  ".s"
  870.         } else {
  871.             set type [file extension [win::CurrentTail]]
  872.         }
  873.     }
  874.     # Now set the mark regexp.
  875.     if {$type == ".s" } {
  876.         # Source file.
  877.         set markExpr {^(###[ ]|####[ ])?[-a-zA-Z0-9]}
  878.     } else {
  879.         # None of the above, so assume that it's output
  880.         set markExpr {^(> )+(###[ ]|####[ ])?[-a-zA-Z0-9]}
  881.     }
  882.     # Mark the file
  883.     while {![catch {search -s -f 1 -r 1 -m 0 -i 1 $markExpr $pos} match]} {
  884.         incr count
  885.         set posBeg [lindex $match 0]
  886.         set posEnd [nextLineStart $posBeg]
  887.         if {[pos::compare $posEnd > [maxPos]]} {set posEnd [maxPos]} 
  888.         set line   [string trimright [getText $posBeg $posEnd]]
  889.         # Get rid of the leading "> " for output files.
  890.         regsub {^ >} $line {} line
  891.         # Get rid of braces.
  892.         regsub -all {\{|\[} $line {(} line
  893.         regsub -all {\}|\]} $line {)} line
  894.         set line  "  $line"
  895.         if {[regsub {  #### } $line {* } line]} {
  896.             incr count -1
  897.         } elseif {[regsub {  ### } $line {• } line]} {
  898.             incr count -1
  899.         } 
  900.         if {[string length $line] > 35} {
  901.             set line "[string range $line 0 35] ..."
  902.         } 
  903.         setNamedMark $line $posBeg $posBeg $posBeg
  904.         set pos $posEnd
  905.     }
  906.     message "This file contains $count commands."
  907. }
  908.  
  909. # ===========================================================================
  910. #
  911. # S Parse Functions
  912. # Borrowed from C++, with modifications.
  913.  
  914. proc S::parseFuncs {} {
  915.     
  916.     global sortFuncsMenu
  917.  
  918.     set funcExpr  {[A-Za-z0-9~_.]+[A-Za-z0-9~_.]+[\t ]*\(}
  919.     set parseExpr {\b([-\w_:.]+)[\t ]*\(}
  920.     
  921.     set pos [minPos]
  922.     set m {}
  923.     while {[set result [search -s -f 1 -r 1 -i 0 -n $funcExpr $pos]] != ""} {
  924.         set pos1 [lindex $result 0]
  925.         set pos2 [lindex $result 1]
  926.         regexp -- $parseExpr [getText $pos1 $pos2] match command
  927.         # Get the line that contains this command.
  928.         set commandLine [getText [lineStart $pos1] $pos2]
  929.         # Strip off anything after the first valid comment.
  930.         regsub -all {\\\#} $commandLine { } commandLine 
  931.         if {[regexp {\#} $commandLine]} {
  932.             set firstComment [string first {#} $commandLine]
  933.             set commandLine [string range $commandLine 0 $firstComment]
  934.         } 
  935.         if {[regexp $command $commandLine]} {
  936.             # The command is still in the line.
  937.             lappend m [list $command $pos1]
  938.         } 
  939.         set pos [nextLineStart $pos2]
  940.     }
  941.     if {$sortFuncsMenu} {
  942.         regsub -all "\[\{\}\]" [lsort -ignore $m] "" m
  943.     } else {
  944.         regsub -all "\[\{\}\]" $m "" m
  945.     }   
  946.     return $m
  947. }
  948.  
  949. # ===========================================================================
  950. # ◊◊◊◊ -------------------- ◊◊◊◊ #
  951. # ◊◊◊◊ S Menu ◊◊◊◊ #
  952. # based upon the Stata menu, contributed by 
  953. # L. Phillip Schumm <pschumm@uchicago.edu>
  954.  
  955. proc sMenu {} {}
  956.  
  957. # Tell Alpha what procedures to use to build all menus, submenus.
  958.  
  959. menu::buildProc sMenu               S::buildMenu
  960. menu::buildProc s+Help              S::buildHelpMenu
  961. menu::buildProc rHelp               S::buildHelpMenu
  962. menu::buildProc sModeKeywords       S::buildKeywordsMenu
  963. menu::buildProc markSFileAs…        S::buildMarkMenu
  964.  
  965. # First build the main S+ menu.
  966.  
  967. proc S::buildMenu {} {
  968.     
  969.     global sMenu SmodeVars
  970.     
  971.     set app    $SmodeVars(application)
  972.     set lowApp [string tolower $SmodeVars(application)]
  973.     
  974.     set menuList [list                                  \
  975.       "${lowApp}HomePage"                               \
  976.       "/S<U<OswitchTo${app}"                            \
  977.       [list Menu -n ${lowApp}Help          -M S {}]        \
  978.       "(-"                                              \
  979.       [list Menu -n sModeKeywords       -M S {}]        \
  980.       [list Menu -n markSFileAs…        -M S {}]        \
  981.       "(-"                                              \
  982.       "/P<U<OprocessFile"                               \
  983.       "/P<U<O<BprocessSelection"                        \
  984.       "(-"                                              \
  985.       "/I<U<OinsertPath"                                \
  986.       "/b<UcontinueCommand"                             \
  987.       "(-"                                              \
  988.       "/N<U<BnextCommand"                               \
  989.       "/P<U<BprevCommand"                               \
  990.       "/S<U<BselectCommand"                             \
  991.       "/I<B<OreformatCommand"                           \
  992.       ]
  993.     set submenus [list ${lowApp}Help sModeKeywords markSFileAs… ]
  994.     return       [list build $menuList S::menuProc $submenus $sMenu]
  995. }
  996.  
  997. # Then build the "S+ Help" submenu.
  998.  
  999. proc S::buildHelpMenu {} {
  1000.     
  1001.     global SmodeVars SPrefsInMenu alpha::platform
  1002.     
  1003.     # Determine which key should be used for "Help", with F8 as option.
  1004.     
  1005.     if {!$SmodeVars(noHelpKey)} {
  1006.         set key "/t"
  1007.     } else {
  1008.         set key "/l"
  1009.     } 
  1010.     
  1011.     # Reverse the local, www key bindings depending on the value of the
  1012.     # 'Local Help" variable.
  1013.     
  1014.     if {$SmodeVars(localHelp) == 0} {
  1015.         set menuList [list                  \
  1016.           "${key}<OwwwCommandHelp…"         \
  1017.           "${key}<IlocalCommandHelp…"       \
  1018.           ]
  1019.     } else {
  1020.         set menuList [list                  \
  1021.           "${key}<OlocalCommandHelp…"       \
  1022.           "${key}<IwwwCommandHelp…"         \
  1023.           ]
  1024.     } 
  1025.     lappend menuList "(-"
  1026.     if {$SmodeVars(application) == "S+"} {
  1027.         lappend menuList "r"
  1028.         lappend menuList "!•s+"
  1029.     } else {
  1030.         lappend menuList "!•r"
  1031.         lappend menuList "s+"
  1032.     }
  1033.     lappend menuList "(-"
  1034.     if {${alpha::platform} == "alpha"} {
  1035.         set prefix "!√"
  1036.     } else {
  1037.         set prefix "!•"
  1038.     } 
  1039.     foreach pref $SPrefsInMenu {
  1040.         if {$SmodeVars($pref)} {
  1041.             lappend menuList "${prefix}$pref"
  1042.         } else {
  1043.             lappend menuList "$pref"
  1044.         }
  1045.     }
  1046.     lappend menuList "(-"
  1047.     lappend menuList "setRApplication"
  1048.     lappend menuList "setS+Application"
  1049.     lappend menuList "(-"
  1050.     lappend menuList "${key}<BsModeHelp"
  1051.     
  1052.     return [list build $menuList S::helpProc {}]
  1053. }
  1054.  
  1055. # Then build the "S Mode Keywords" submenu.
  1056.  
  1057. proc S::buildKeywordsMenu {} {
  1058.     
  1059.     set menuList [list \
  1060.       "listKeywords"                    \
  1061.       "checkKeywords"                   \
  1062.       "addNewCommands"                  \
  1063.       "addNewArguments"                 \
  1064.       ]
  1065.     return [list build $menuList S::keywordsProc {}]
  1066. }
  1067.  
  1068. # Then build the "Mark S File As" submenu.
  1069.  
  1070. proc S::buildMarkMenu {} {
  1071.     
  1072.     global SmodeVars alpha::platform
  1073.     
  1074.     set menuList [list                  \
  1075.       "source"                          \
  1076.       "output"                          \
  1077.       "(-"                              \
  1078.       ]
  1079.     if {${alpha::platform} == "alpha"} {
  1080.         set prefix "!√"
  1081.     } else {
  1082.         set prefix "!•"
  1083.     } 
  1084.     if {$SmodeVars(autoMark)} {
  1085.         lappend menuList "${prefix}autoMark"
  1086.     } else {
  1087.         lappend menuList "autoMark"        
  1088.     }
  1089.     return [list build $menuList S::markFileProc {}]
  1090. }
  1091.  
  1092. proc S::rebuildMenu {{menuName "sMenu"} {pref ""}} {
  1093.     menu::buildSome $menuName
  1094. }
  1095.  
  1096. # Dim some menu items when there are no open windows.
  1097. set menuItems {
  1098.     processFile processSelection markSFileAs… 
  1099.     insertPath 
  1100.     nextCommand prevCommand selectCommand
  1101. }
  1102. foreach i $menuItems {
  1103.     hook::register requireOpenWindowsHook [list sMenu $i] 1
  1104. unset i menuItems 
  1105.  
  1106. # Now we actually build the S+ menu.
  1107.  
  1108. menu::buildSome sMenu
  1109.  
  1110. # ===========================================================================
  1111. # ◊◊◊◊ S-Plus menu support ◊◊◊◊ #
  1112.  
  1113. # This is the procedure called for all main menu items.
  1114.  
  1115. proc S::menuProc {menu item} {S::$item}
  1116.  
  1117. # Give a beta message for untested features / menu items.
  1118.  
  1119. proc S::betaMessage {{kill 1}} {
  1120.     
  1121.     beep ; message "Sorry, this feature has not been fully implemented."
  1122.     if {$kill} {return -code return}
  1123. }
  1124.  
  1125. # ===========================================================================
  1126. # Open the S / R+ home page.
  1127.  
  1128. proc S::s+HomePage {{app "S+"}} {
  1129.     
  1130.     global SmodeVars
  1131.     
  1132.     if {$app == ""} {set app $SmodeVars(application)} 
  1133.     set lowApp [string tolower $app]
  1134.  
  1135.     url::execute $SmodeVars(${lowApp}HomePage)
  1136. }
  1137.  
  1138. proc S::rHomePage {} {S::s+HomePage "R"}
  1139.  
  1140. # ===========================================================================
  1141. # Switch to S-Plus or R application
  1142.  
  1143. proc S::switchToS+ {{app "S+"}} {
  1144.     
  1145.     global SmodeVars
  1146.     
  1147.     if {$app == ""} {set app $SmodeVars(application)}
  1148.  
  1149.     app::launchFore '[S::sig $app]'
  1150. }
  1151.  
  1152. proc S::switchToR {} {S::switchToS+ "R"}
  1153.  
  1154.  
  1155. # ===========================================================================
  1156. # Return the S+ / R signature.
  1157.  
  1158. proc S::sig {{app "S+"}} {
  1159.     
  1160.     global SmodeVars tcl_platform
  1161.     
  1162.     if {$app == ""} {set app $SmodeVars(application)}
  1163.  
  1164.     set lowApp [string tolower $app]
  1165.     set capApp [string toupper $app]
  1166.     set pf     $tcl_platform(platform)
  1167.  
  1168.     if {$pf == "macintosh"} {
  1169.         # Make sure that the Macintosh application for the signature exists.
  1170.         if {[catch {nameFromAppl $SmodeVars(${lowApp}Sig)}]} {
  1171.             alertnote "Looking for the $capApp application ..."
  1172.             S::setApplication $lowApp
  1173.         }
  1174.     } elseif {$pf == "windows" || $pf == "unix"} {
  1175.         # Make sure that the Windows application for the signature exists. 
  1176.         # We assume that this will work for unix, too.
  1177.         if {![file exists $SmodeVars(${lowApp}Sig)]} {
  1178.             alertnote "Looking for the $capApp application ..."
  1179.             S::setApplication $lowApp
  1180.         }
  1181.     }
  1182.     return $SmodeVars(${lowApp}Sig)
  1183. }
  1184.  
  1185. # ===========================================================================
  1186. # Set Application
  1187. # Prompt the user to locate the local S application.
  1188.  
  1189. proc S::setApplication {{app ""}} {
  1190.     
  1191.     global mode SmodeVars
  1192.     
  1193.     if {$app == ""} {set app $SmodeVars(application)} 
  1194.  
  1195.     set lowApp [string tolower $app]
  1196.     set capApp [string toupper $app]
  1197.     
  1198.     set newSig ""
  1199.     set newSig [dialog::askFindApp $capApp $SmodeVars(${lowApp}Sig)]
  1200.     
  1201.     if {$newSig != ""} {
  1202.         set SmodeVars(${lowApp}Sig) "$newSig"
  1203.         set oldMode $mode
  1204.         set mode "S"
  1205.         synchroniseModeVar "${lowApp}Sig" $SmodeVars(${lowApp}Sig)
  1206.         set mode $oldMode
  1207.         message "The $capApp signature has been changed to \"$newSig\"."
  1208.     } else {
  1209.         message "Cancelled."
  1210.     }
  1211. }
  1212.  
  1213. # ===========================================================================
  1214. # ◊◊◊◊ Help ◊◊◊◊ #
  1215.  
  1216. proc S::helpProc {menu item} {
  1217.     
  1218.     global SmodeVars SPrefsInMenu
  1219.     
  1220.     if {$item == "wwwCommandHelp"} {
  1221.         S::wwwCommandHelp
  1222.     } elseif  {$item == "localCommandHelp"} {
  1223.         S::localCommandHelp
  1224.     } elseif {$item == "r" || $item == "s+"} {
  1225.         S::selectApplication $item
  1226.         S::rebuildMenu
  1227.     } elseif {[lsearch -exact $SPrefsInMenu $item] != -1} {
  1228.         S::flagFlip $item
  1229.         S::rebuildMenu
  1230.     } elseif {$item == "setRApplication"} {
  1231.         S::setApplication "r"
  1232.     } elseif {$item == "setS+Application"} {
  1233.         S::setApplication "s+"
  1234.     } elseif {$item == "sModeHelp"} {
  1235.         package::helpFile "S"
  1236.     } else {
  1237.         S::$item
  1238.     } 
  1239. }
  1240.  
  1241. # Choose between R and S+
  1242.  
  1243. proc S::selectApplication {app} {
  1244.     
  1245.     global mode SmodeVars
  1246.     
  1247.     set app [string toupper $app]
  1248.  
  1249.     set SmodeVars(application) $app
  1250.     set oldMode $mode
  1251.     set mode "S"
  1252.     synchroniseModeVar application $SmodeVars(application)
  1253.     set mode $oldMode
  1254.     message "Default application is now $app."
  1255. }
  1256.  
  1257. # ===========================================================================
  1258. # ◊◊◊◊ Keywords ◊◊◊◊ #
  1259.  
  1260. proc S::keywordsProc {menuName item} {
  1261.  
  1262.     global Scmds
  1263.     
  1264.     if {$item == "listKeywords"} {
  1265.         set keywords [listpick -l -p "Current S mode keywords…" $Scmds]
  1266.         foreach keyword $keywords {
  1267.             S::checkKeywords $keyword
  1268.         }
  1269.     } elseif {$item == "addNewCommands" || $item == "addNewArguments"} {
  1270.         set item [string trimleft $item "addNew"]
  1271.         if {$item == "Commands" && [llength [winNames]] && [askyesno \
  1272.           "Would you like to add all of the \"extra\" commands from this window\
  1273.           to the \"Add Commands\" preference?"] == "yes"} {
  1274.             S::addWindowCommands
  1275.         } else {
  1276.             S::addKeywords $item
  1277.         }
  1278.     } else {
  1279.         S::$item
  1280.     } 
  1281. }
  1282.  
  1283. # ===========================================================================
  1284. # S::addWindowCommands
  1285. # Add all of the "extra" commands which appear in entries in this window.
  1286.  
  1287. proc S::addWindowCommands {} {
  1288.     
  1289.     global mode Scmds SmodeVars
  1290.     
  1291.     if {![llength [winNames]]} {
  1292.         message "Cancelled -- no current window!"
  1293.         return
  1294.     } 
  1295.     
  1296.     message "Scanning [win::CurrentTail] for all commands…"
  1297.     
  1298.     set pos  [minPos]
  1299.     set pat1 {[A-Za-z0-9~_.]+[A-Za-z0-9~_.]+[\t ]*\(}
  1300.     set pat2 {\b([-\w_:.]+)\s*\(}
  1301.     while {![catch {search -f 1 -r 1 $pat1 $pos} match]} {
  1302.         set pos  [nextLineStart [lindex $match 1]]
  1303.         set pos1 [lindex $match 0]
  1304.         set pos2 [lindex $match 1]
  1305.         regexp -- $pat2 [getText $pos1 $pos2] match aCommand
  1306.         # Get the line that contains this command.
  1307.         set commandLine [getText [lineStart $pos1] $pos2]
  1308.         # Strip off anything after the first valid comment.
  1309.         regsub -all {\\\#} $commandLine { } commandLine 
  1310.         if {[regexp {\#} $commandLine]} {
  1311.             set firstComment [string first {#} $commandLine]
  1312.             set commandLine [string range $commandLine 0 $firstComment]
  1313.         } 
  1314.         if {[regexp $aCommand $commandLine] && ![lcontains Scmds $aCommand]} {
  1315.             # The command is still in the line, and not recognized.
  1316.             append SmodeVars(addCommands) " $aCommand"
  1317.         } 
  1318.     }
  1319.     set SmodeVars(addCommands) [lsort [lunique $SmodeVars(addCommands)]]
  1320.     set oldMode $mode
  1321.     set mode "S"
  1322.     synchroniseModeVar addCommands $SmodeVars(addCommands)
  1323.     set mode $oldMode
  1324.     if {[llength $SmodeVars(addCommands)]} {
  1325.         S::colorizeS
  1326.         listpick -p "The \"Add Commands\" preference includes:" \
  1327.           $SmodeVars(addCommands)
  1328.         message "Use the \"Mode Prefs --> Preferences\" menu item to edit keyword lists."
  1329.     } else {
  1330.         message "No \"extra\" commands from this window were found."
  1331.     } 
  1332. }
  1333.  
  1334. # ===========================================================================
  1335. # S::addKeywords
  1336. # Prompt the user to add keywords for a given category.
  1337.  
  1338. # Query existing lists of keywords, and add to the mode preferences.
  1339.  
  1340. proc S::addKeywords {category {keywords ""}} {
  1341.     
  1342.     global mode SmodeVars
  1343.     
  1344.     if {$keywords == ""} {
  1345.         set keywords [prompt "Enter new $SmodeVars(application) $category:" ""]
  1346.     }
  1347.     
  1348.     # Check to see if the keyword is already defined.
  1349.     foreach keyword $keywords {
  1350.         set checkStatus [S::checkKeywords $keyword 1 0]
  1351.         if {$checkStatus != 0} {
  1352.             alertnote "Sorry, \"$keyword\" is already defined\
  1353.               in the $checkStatus list."
  1354.             message "Cancelled."
  1355.             return -code return
  1356.         } 
  1357.     }
  1358.     # Keywords are all new, so add them to the appropriate mode preference.
  1359.     append SmodeVars(add$category) " $keywords"
  1360.     set SmodeVars(add$category) [lsort $SmodeVars(add$category)]
  1361.     set oldMode $mode
  1362.     set mode "S"
  1363.     synchroniseModeVar add$category $SmodeVars(add$category)
  1364.     set mode $oldMode
  1365.     S::colorizeS
  1366.     message "\"$keywords\" added to $category preference."
  1367. }
  1368.  
  1369. proc S::checkKeywords {{newKeywordList ""} {quietly 0} {noPrefs 0}} {
  1370.     
  1371.     global SmodeVars
  1372.     
  1373.     global SCommands  SUserCommands SArguments SUserArguments SMassLibrary
  1374.     
  1375.     set type 0
  1376.     if {$newKeywordList == ""} {
  1377.         set quietly 0
  1378.         set newKeywordList [prompt "Enter S mode keywords to be checked:" ""]
  1379.     }
  1380.     # Check to see if the new keyword(s) is already defined.
  1381.     foreach newKeyword $newKeywordList {
  1382.         if {[lsearch -exact $SCommands $newKeyword] != "-1"} {
  1383.             set type SCommands
  1384.         } elseif {[lsearch -exact $SUserCommands $newKeyword] != "-1"} {
  1385.             set type SUserCommands
  1386.         } elseif {[lsearch -exact $SArguments $newKeyword] != "-1"} {
  1387.             set type SArguments
  1388.         } elseif {[lsearch -exact $SUserArguments $newKeyword] != "-1"} {
  1389.             set type SUserArguments
  1390.         } elseif {[lsearch -exact $SMassLibrary $newKeyword] != "-1"} {
  1391.             set type SMassLibrary
  1392.         } elseif {!$noPrefs && \
  1393.           [lsearch -exact $SmodeVars(addCommands) $newKeyword] != "-1"} {
  1394.             set type SmodeVars(addCommands)
  1395.         } elseif {!$noPrefs && \
  1396.           [lsearch -exact $SmodeVars(addArguments) $newKeyword] != "-1"} {
  1397.             set type SmodeVars(addArguments)
  1398.         }
  1399.         if {$quietly} {
  1400.             # When this is called from other code, it should only contain
  1401.             # one keyword to be checked, and we'll return it's type.
  1402.             return "$type"
  1403.         } elseif {!$quietly && $type == 0} {
  1404.             alertnote "\"$newKeyword\" is not currently defined\
  1405.               as a S mode keyword"
  1406.         } elseif {$type != 0} {
  1407.             # This will work for any other value for "quietly", such as 2
  1408.             alertnote "\"$newKeyword\" is currently defined as a keyword\
  1409.               in the \"$type\" list."
  1410.         } 
  1411.         set type 0
  1412.     }
  1413. }
  1414.  
  1415. # ===========================================================================
  1416. # ◊◊◊◊ Processing ◊◊◊◊ #
  1417.  
  1418. # ===========================================================================
  1419. # Process File
  1420. # Send entire file to S+ / R for processing, adding carriage return at end
  1421. # of file if necessary.
  1422. # Optional "f" argument allows this to be called by other code, or to be 
  1423. # sent via a Tcl shell window.
  1424.  
  1425. proc S::processFile {{f ""} {app ""}} {
  1426.     
  1427.     global SmodeVars
  1428.     
  1429.     if {$f != ""} {file::openAny $f}
  1430.     set f [win::Current]
  1431.  
  1432.     if {$app == ""} {set app $SmodeVars(application)}
  1433.  
  1434.     set lowApp [string tolower $app]
  1435.     set capApp [string toupper $app]
  1436.  
  1437.     set dirtyWindow [winDirty]
  1438.     set dontSave 0
  1439.     if {$dirtyWindow && [askyesno \
  1440.       "Do you want to save the file before sending it to $capApp?"] == "yes"} {
  1441.         save
  1442.     } else {
  1443.         set dontSave 1
  1444.     } 
  1445.     if {!$dontSave && [lookAt [pos::math [maxPos] - 1]] != "\r"} {
  1446.         set pos [getPos]
  1447.         goto [maxPos]
  1448.         insertText "\r"
  1449.         goto $pos
  1450.         alertnote "Carriage return added to end of file."
  1451.         save
  1452.     }
  1453.  
  1454.     app::launchBack '[S::sig $capApp]'
  1455.     sendOpenEvent noReply '[S::sig $capApp]' $f
  1456.     switchTo '[S::sig $capApp]'
  1457. }
  1458.  
  1459. # ===========================================================================
  1460. # Process Selection
  1461. # Procedure to implement transfer of selected lines to S+ / R for processing.
  1462.  
  1463. proc S::processSelection {{selection ""} {app ""}} {
  1464.     
  1465.     global PREFS SmodeVars
  1466.     
  1467.     if {$app == ""} {set app $SmodeVars(application)}
  1468.  
  1469.     set lowApp [string tolower $app]
  1470.     set capApp [string toupper $app]
  1471.  
  1472.     if {$selection == ""} {
  1473.         if {![isSelection]} {
  1474.             message "No selection -- cancelled."
  1475.             return
  1476.         } else {
  1477.             set selection [getSelect]
  1478.         } 
  1479.     }
  1480.     file::ensureDirExists [file join $PREFS S-tmp]
  1481.     set newFile [file join $PREFS S-tmp temp-S.s]
  1482.     file::writeAll $newFile $selection 1
  1483.  
  1484.     app::launchBack '[S::sig $capApp]'
  1485.     sendOpenEvent noReply '[S::sig $capApp]' $newFile
  1486.     switchTo '[S::sig $capApp]'
  1487. }
  1488.  
  1489. proc S::quitHook {} {temp::cleanup S-tmp}
  1490.  
  1491. # ===========================================================================
  1492. # ◊◊◊◊ Marks ◊◊◊◊ #
  1493.  
  1494. proc S::markFileProc {menu item} {
  1495.  
  1496.     if {$item == "source"} {
  1497.         S::MarkFile {.s}
  1498.     } elseif {$item == "output"} {
  1499.         # doesn't really matter what we put for the mark file "type" here,
  1500.         # since output is the default if other "if ..." cases aren't met.
  1501.         S::MarkFile {.out}
  1502.     } elseif {$item == "autoMark"} {
  1503.         S::flagFlip autoMark
  1504.         S::rebuildMenu markS+FileAs…
  1505.         S::rebuildMenu markRFileAs…
  1506.     }
  1507. }
  1508.  
  1509. # ===========================================================================
  1510. # ◊◊◊◊ Insertions ◊◊◊◊ #
  1511.  
  1512. proc S::insertPath {} {
  1513.     
  1514.     global file::separator
  1515.     
  1516.     set path ""
  1517.     set t    ""
  1518.     append t "\"${file::separator}"
  1519.     set path [getfile "Choose path of target file:"]
  1520.     if {$path != ""} {
  1521.         append t $path
  1522.         append t "\""
  1523.         insertText $t
  1524.     }
  1525. }
  1526.  
  1527. # ===========================================================================
  1528. # ◊◊◊◊ Navigation ◊◊◊◊ #
  1529.  
  1530. # Next/Prev command can simply return the position of the next command
  1531. # (quietly == 1), move the cursor to the next command (placing the cursor
  1532. # at the top of the window if toTop == 1), extend the current selection to
  1533. # the end of the this command, or (if the current command is already
  1534. # highlighted in its entirety) extend the current selection to the end of
  1535. # the next command.
  1536.  
  1537. proc S::nextCommand {{quietly 0} {toTop 0}} {
  1538.     
  1539.     if {[pos::compare [selEnd] == [maxPos]]} {
  1540.         set pos [maxPos]
  1541.     } else {
  1542.         set pos [pos::math [selEnd] + 1]
  1543.     } 
  1544.     set pat {^[^\r\n\t \#\}\)]}
  1545.     if {![catch {search -f 1 -r 1 $pat $pos} match]} {
  1546.         set pos [lineStart [lindex $match 1]]
  1547.     } else {
  1548.         set pos [maxPos]
  1549.     }
  1550.     if {$quietly} {
  1551.         return $pos
  1552.     } elseif {[isSelection]} {
  1553.         set limit1 [lindex [S::getCommand [selEnd]] 1]
  1554.         set limit2 [lindex [S::getCommand $pos    ] 1]
  1555.         if {$limit2 == "-1"} {set limit2 [maxPos]}
  1556.         if {$limit1 == "-1"} {set limit1 $limit2}
  1557.         if {[pos::compare [selEnd] < $limit1]} {
  1558.             select [getPos] $limit1
  1559.         } else {
  1560.             select [getPos] $limit2
  1561.         } 
  1562.     } elseif {$pos == [maxPos]} {
  1563.         message "No further commands in the file."
  1564.         return
  1565.     } else {
  1566.         goto $pos
  1567.         message [getText $pos [nextLineStart $pos]]
  1568.     } 
  1569.     if {$toTop} {insertToTop}
  1570. }
  1571.  
  1572. proc S::prevCommand {{quietly 0} {toTop 0}} {
  1573.     
  1574.     if {[pos::compare [getPos] == [minPos]]} {
  1575.         set pos [minPos]
  1576.     } else {
  1577.         set pos [pos::math [getPos] - 1]
  1578.     } 
  1579.     set pat {^[^\r\n\t \#\}\)]}
  1580.     if {![catch {search -f 0 -r 1 $pat $pos} match]} {
  1581.         set pos [lineStart [lindex $match 0]]
  1582.     } else {
  1583.         set pos [minPos]
  1584.     }
  1585.     if {$quietly} {
  1586.         return $pos
  1587.     } elseif {[isSelection]} {
  1588.         # Going backwards is actually easier with selections.
  1589.         select $pos [selEnd]
  1590.     } elseif {$pos == [minPos]} {
  1591.         message "No further commands in the file."
  1592.         return
  1593.     } else {
  1594.         goto $pos
  1595.         message [getText $pos [nextLineStart $pos]]
  1596.     } 
  1597.     if {$toTop} {insertToTop}
  1598.     return $pos
  1599. }
  1600.  
  1601. proc S::searchFunc {direction} {
  1602.     
  1603.     if {$direction} {
  1604.         S::nextCommand
  1605.     } else {
  1606.         S::prevCommand
  1607.     }
  1608. }
  1609.  
  1610. proc S::selectCommand {} {
  1611.     
  1612.     set pos    [getPos]
  1613.     set limits [S::getCommand $pos]
  1614.     set posBeg [lindex $limits 0]
  1615.     set posEnd [lindex $limits 1]
  1616.     
  1617.     if {$posBeg != "-1" && $posEnd != "-1" && \
  1618.       [pos::compare $pos >= $posBeg] && [pos::compare $pos <= $posEnd]} {
  1619.         select $posBeg $posEnd
  1620.     } else {
  1621.         message "The cursor is not within a command."
  1622.         error "The cursor is not within a command."
  1623.     } 
  1624. }
  1625.  
  1626. proc S::copyCommand {{quietly 0}} {
  1627.     
  1628.     set pos [getPos]
  1629.     if {[set posBeg [lindex [S::getCommand $pos] 0]] != "-1"} {
  1630.         goto $posBeg
  1631.         forwardWord
  1632.         set posEnd [getPos]
  1633.         if {!$quietly} {
  1634.             select $posBeg $posEnd
  1635.             copy
  1636.             message "\"[getText $posBeg $posEnd]\" copied to clipboard."
  1637.         } 
  1638.         goto $pos
  1639.         return [getText $posBeg $posEnd]
  1640.     } elseif {!$quietly} {
  1641.         message "The cursor is not within a command."
  1642.     }
  1643.     return ""
  1644. }
  1645.  
  1646. proc S::reformatCommand {} {
  1647.     
  1648.     if {![isSelection]} {S::selectCommand} 
  1649.     message "Reformatting …"
  1650.     ::indentRegion
  1651.     goto [pos::math [getPos] -1]
  1652.     goto [S::nextCommand 1]
  1653.     message "Reformatted."
  1654. }
  1655.  
  1656. proc S::getCommand {pos} {
  1657.     
  1658.     set pos1 [pos::math [nextLineStart $pos] - 1]
  1659.     set pat {^[^\r\n\t \}\)]}
  1660.     set posBeg "-1"
  1661.     set posEnd "-1"
  1662.     if {![catch {search -f 0 -r 1 $pat $pos1} match]} {
  1663.         set posBeg [lindex $match 0]
  1664.         set pos2   [nextLineStart $posBeg]
  1665.         if {![catch {search -f 1 -r 1 $pat $pos2} match]} {
  1666.             set posEnd [lindex $match 0]
  1667.         } else {
  1668.             set posEnd [maxPos]
  1669.         } 
  1670.         # Now back up to remove empty or commented lines.
  1671.         set posEndPrev [pos::math $posEnd - 1]
  1672.         set prevLine [getText [lineStart $posEndPrev] $posEndPrev]
  1673.         while {[regexp {^[\t ]*$} $prevLine]} {
  1674.             set posEnd [lineStart $posEndPrev]
  1675.             set posEndPrev [pos::math $posEnd - 1]
  1676.             set prevLine [getText [lineStart $posEndPrev] $posEndPrev]
  1677.         }
  1678.     } 
  1679.     return [list $posBeg $posEnd]
  1680. }
  1681.  
  1682. # ===========================================================================
  1683. # ◊◊◊◊ --------------------- ◊◊◊◊ #
  1684. # ◊◊◊◊ version history ◊◊◊◊ #
  1685. #  modified by  vers#  reason
  1686. #  -------- --- ------ -----------
  1687. #  01/28/20 cbu 1.0.1  First created S mode, based upon other modes found 
  1688. #                        in Alpha's distribution.   Commands are based on 
  1689. #                        release number 3.3, taken from the "common commands" 
  1690. #                        as listed in Venable and Ripley's "Modern Applied 
  1691. #                        Statistics with S-PLUS", second edition.
  1692. #  03/02/20 cbu 1.0.2  Minor modifications to comment handling.
  1693. #  03/20/00 cbu 1.0.3  Minor update of keywords dictionaries.
  1694. #                      Removed markFile and parseFuncs procs, because they're 
  1695. #                        not stable or properly worked out.
  1696. #  04/01/00 cbu 1.0.4  Fixed a little bug with "comment box".
  1697. #                      Added new preferences to allow the user to optionally 
  1698. #                        use $ as a Magic Character, and to enter additional 
  1699. #                        commands and options.  
  1700. #                      Removed the "Either/Ors" category, put them into arguments.
  1701. #                      Added the C++ MarkFile and parseFuncs procs.
  1702. #                      Added "Update Colors" proc to avoid need for a restart
  1703. #  04/08/00 cbu 1.0.5  Unset obsolete preferences from earlier versions.
  1704. #                      Added "Continue Comment" and "Electric Return Over-ride".
  1705. #                      Renamed "Update Colors" to "Update Preferences".
  1706. #                      Added the tcl indentation routines.
  1707. #  04/16/00 cbu 1.1    Renamed to sMode.tcl
  1708. #                      Wrote my own "Mark File" proc, replaced the C++ MarkFile.
  1709. #                      Removed indentation routines, at least for now.
  1710. #  06/22/00 cbu 1.2    "Mark File" now recognizes headings as well as commands.
  1711. #                      Completions, Completions Tutorial added.
  1712. #                      "Reload Completions", referenced by "Update Preferences".
  1713. #                      Better support for user defined keywords.
  1714. #                      Removed "Continue Comment", now global in Alpha 7.4.
  1715. #                      Added command double-click for on-line help.
  1716. #                      <shift, control>-<command> double-click syntax info.
  1717. #                        (Foundations, at least.  Ongoing project.)
  1718. #  08/07/00 cbu 1.2.1  DblClick now looks for variable (etc) definitions
  1719. #                        in current file.
  1720. #                      Added message if no matching ")".
  1721. #                      Mark File can mark a frequencies file.
  1722. #                      Beta-version of an S-Plus menu, based on the Stata menu.
  1723. #                        No Macintosh versions of S-Plus or R limit its
  1724. #                        functionality ...
  1725. #                      Added "s+Sig" preference to allow user to find
  1726. #                        local application if necessary, in case S+/R is ever
  1727. #                        ported to the Macintosh.
  1728. #                      Added S::sig which returns S-Plus signature.
  1729. #  08/28/00 cbu 1.2.2  Added some of the flag preferences to "S+/R Help" menu.
  1730. #                      Added "flagFlip" to update preference bullets in menu.
  1731. #                      Added "application" preference, used in menu.
  1732. #                      Added "rSig" preference.
  1733. #                      Added a "noHelpKey" preference, which switches the
  1734. #                        "help" key binding to F8.
  1735. #                      Added "Add New Commands / Arguments" to "S+/R Help" menu.
  1736. #                      Added "Set S+/R Application to "S+/R Help" menu.
  1737. #                      Starting to differentiate code based on platform.
  1738. #                      Including a "beta message" for untested menu items.
  1739. #  11/05/00 cbu 1.3    Added "next/prevCommand", "selectCommand", and
  1740. #                        "copyCommand" procs to menu.
  1741. #                      Added "S::indentLine".
  1742. #                      Added "S::reformatCommand" to menu.
  1743. #                      Added "S::continueCommand" to over-ride indents. 
  1744. #                      "S::reloadCompletions" is now obsolete.
  1745. #                      "S::updatePreferences" is now obsolete.
  1746. #                      "S::colorizeS" now takes care of setting all 
  1747. #                        keyword lists, including Scmds.
  1748. #                      Cleaned up completion procs.  This file never has to be
  1749. #                        reloaded.  (Similar cleaning up for "S::DblClick").
  1750. #  11/16/00 cbu 2.0    New url prefs handling requires 7.4b21
  1751. #                      Added "Home Page" pref, menu item.
  1752. #                      Removed  hook::register requireOpenWindowsHook from
  1753. #                        mode declaration, put it after menu build.
  1754. #  12/19/00 cbu 2.1    The menu proc "Add Commands" now includes an option
  1755. #                        to grab all of the "extra" command from the current
  1756. #                        window, using S::addWindowCommands.
  1757. #                      Added "Keywords" submenu, "List Keywords" menu item.
  1758. #                      Big cleanup of ::sig, ::setApplication, processing ...
  1759. #  01/25/01 cbu 2.1.1  Bug fix for S::processSelection/File.
  1760. #                      Bug fix for comment characters.
  1761.  
  1762. # ===========================================================================
  1763. # .
  1764.  
  1765.